package com.rightsidetech.commom.utils;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.RandomUtil;
import com.aliyun.oss.OSS;
import com.rightsidetech.commom.base.ResponseData;
import com.rightsidetech.commom.config.AliyunOSSConfig;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.MultimediaInfo;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Package: com.rightsidetech.http.utils
 * @ClassName: UplodeUtils
 * @Author: yinj
 * @CreateTime: 2021/6/3 15:50
 * @Description: TODO 文件上传工具类 OSS
 */
@Slf4j
public class UplodeUtils {

    /**
     * 图片：png ，jpg，jpeg，bmp，gif
     * 音频：mp3，m4a
     * 文档：doc，docx，xls，xlsx，txt，pdf，ppt，pptx
     * 视频：mp4
     */

    // 允许上传的格式 图片/视频/音频/文档
    private static final String[] IMAGE_TYPE = new String[]{".jpg", ".jpeg", ".gif", ".png", ".bmp"};

    private static final String[] AUDIO_TYPE = new String[]{".mp3", ".m4a"};

    private static final String[] DPC_TYPE = new String[]{".doc", ".docx", ".xls", ".xlsx", ".txt", ".pdf", ".ppt", ".pptx"};

    private static final String[] VIDEO_TYPE = new String[]{".mp4"};

    //视频大小限制100MB
    private static final BigDecimal MAX_VIDEO_SIZE = new BigDecimal(100);
    //视频时长限制60秒
    private static final Long MAX_TIMES = 60L;
    //图片大小限制5Mb
    private static final BigDecimal MAX_IMAGE_SIZE = new BigDecimal(5);
    //音频大小限制30Mb
    private static final BigDecimal MAX_AUDIO_SIZE = new BigDecimal(30);
    //文档大小限制20Mb
    private static final BigDecimal MAX_DOC_SIZE = new BigDecimal(20);

    private static final Pattern pattern = Pattern.compile("[\u4e00-\u9fa5]");


    /**
     * 单个文件上传
     *
     * @param multipartFile
     * @return
     */
    public static ResponseData<String> upload(MultipartFile multipartFile, OSS ossClient, AliyunOSSConfig ossConfig) throws Exception {
        // 1. 对上传的图片进行校验: 这里简单校验后缀名
        // 另外可通过ImageIO读取图片的长宽来判断是否是图片,校验图片的大小等。
//        boolean isLegal = false;
//        for (String type : IMAGE_TYPE) {
//            if (StringUtils.endsWithIgnoreCase(multipartFile.getOriginalFilename(), type)) {
//                isLegal = true;
//                break;  // 只要与允许上传格式其中一个匹配就可以
//            }
//        }
//        if (!isLegal) {
//            return ResponseData.fail("文件格式错误");
//        }

        // 2. 准备上传API的参数
        String fileName = multipartFile.getOriginalFilename();
        String filePath = getFilePath(fileName, null);

        // 3. 上传至阿里OSS
        try {
            ossClient.putObject(ossConfig.getBucketName(), filePath, new ByteArrayInputStream(multipartFile.getBytes()));

            //TODO  下载到指定路径
//            ObjectMetadata object = ossClient.getObject(new GetObjectRequest(aliyunOSSConfig.getBucketName(), "images/2021/06/01/16225257250659499002.jpg"), new File("C:\\Users\\qiaoyf\\Desktop\\16225257250659499002.jpg"));

        } catch (IOException e) {
            e.printStackTrace();
            return ResponseData.fail("上传失败");
        }

        return ResponseData.success(ossConfig.getImageUrl() + filePath);

    }

    /**
     * 批量文件上传
     *
     * @param files
     * @return
     */
    public static ResponseData<String[]> moreUplode(MultipartFile[] files, OSS ossClient, AliyunOSSConfig ossConfig) throws Exception {
        String[] stars = new String[files.length];
        //校验格式
        for (MultipartFile file : files) {
            boolean isLegal = false;
            for (String type : IMAGE_TYPE) {
                if (StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), type)) {
                    isLegal = true;
                    break;  // 只要与允许上传格式其中一个匹配就可以
                }
            }
            if (!isLegal) {
                return ResponseData.fail(file.getOriginalFilename() + "文件格式错误");
            }
        }

        //循环获取file数组中得文件
        for (int i = 0; i < files.length; i++) {
            MultipartFile file = files[i];
            String fileName = file.getOriginalFilename();
            String filePath = getFilePath(fileName, null);

            try {
                ossClient.putObject(ossConfig.getBucketName(), filePath, new ByteArrayInputStream(file.getBytes()));
            } catch (IOException e) {
                e.printStackTrace();
                return ResponseData.fail("上传失败");
            }
            stars[i] = ossConfig.getImageUrl() + filePath;
        }
        return ResponseData.success(stars);
    }

    /**
     * 后台批量文件上传
     *
     * @param files
     * @return
     */
    public static ResponseData<String[]> adminMoreUplode(MultipartFile[] files, OSS ossClient, AliyunOSSConfig ossConfig) throws Exception {
        String[] stars = new String[files.length];
        //校验格式
        for (MultipartFile file : files) {
            boolean isLegal = false;
            //图片
            for (String type : IMAGE_TYPE) {
                if (StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), type)) {
                    isLegal = true;
                    //校验大小
                    BigDecimal fileSize = getFileSize(file);
                    if (fileSize.compareTo(BigDecimal.ZERO) <= 0) {
                        return ResponseData.fail(file.getOriginalFilename() + "文件不合法");
                    }
                    if (fileSize.compareTo(MAX_IMAGE_SIZE.multiply(new BigDecimal(1024))) > 0) {
                        return ResponseData.fail("图片文件大小不能大于" + MAX_IMAGE_SIZE + "MB");
                    }
                    break;
                }
            }
            //视频
            for (String type : VIDEO_TYPE) {
                if (StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), type)) {
                    isLegal = true;
                    BigDecimal fileSize = getFileSize(file);
                    if (fileSize.compareTo(BigDecimal.ZERO) <= 0) {
                        return ResponseData.fail(file.getOriginalFilename() + "文件不合法");
                    }
                    if (fileSize.compareTo(MAX_VIDEO_SIZE.multiply(new BigDecimal(1024))) > 0) {
                        return ResponseData.fail("视频文件大小不能大于" + MAX_VIDEO_SIZE + "MB");
                    }
                    break;
                }
            }
            //音频
            for (String type : AUDIO_TYPE) {
                if (StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), type)) {
                    isLegal = true;
                    BigDecimal fileSize = getFileSize(file);
                    if (fileSize.compareTo(BigDecimal.ZERO) <= 0) {
                        return ResponseData.fail(file.getOriginalFilename() + "文件不合法");
                    }
                    if (fileSize.compareTo(MAX_AUDIO_SIZE.multiply(new BigDecimal(1024))) > 0) {
                        return ResponseData.fail("音频文件大小不能大于" + MAX_AUDIO_SIZE + "MB");
                    }
                    break;
                }
            }
            //文档
            for (String type : DPC_TYPE) {
                if (StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), type)) {
                    isLegal = true;
                    BigDecimal fileSize = getFileSize(file);
                    if (fileSize.compareTo(BigDecimal.ZERO) <= 0) {
                        return ResponseData.fail(file.getOriginalFilename() + "文件不合法");
                    } else if (fileSize.compareTo(MAX_DOC_SIZE.multiply(new BigDecimal(1024))) > 0) {
                        return ResponseData.fail("文档文件大小不能大于" + MAX_DOC_SIZE + "MB");
                    }
                    break;
                }
            }


            if (!isLegal) {
                return ResponseData.fail(file.getOriginalFilename() + "文件格式不允许");
            }

        }

        //循环获取file数组中得文件
        for (int i = 0; i < files.length; i++) {
            MultipartFile file = files[i];
            String fileName = file.getOriginalFilename();
            FileInfo fileInfo = null;
            if (!StringUtils.isEmpty(fileName) && fileName.contains(".mp4")) {
                //有中文替换名称
                Matcher m = pattern.matcher(fileName);
                if (m.find()) {
                    fileName = UUID.randomUUID().toString().replace("-", "") + ".mp4";
                }
                fileInfo = getVideoTime(file);
            }
            if (!StringUtils.isEmpty(fileName) && (fileName.contains(".jpg") || fileName.contains(".jpeg") || fileName.contains(".gif")
                    || fileName.contains(".png") || fileName.contains(".bmp"))) {
                fileInfo = getpictureFileInfo(file);
            }

            String filePath = getFilePath(fileName, fileInfo);

            try {
                ossClient.putObject(ossConfig.getBucketName(), filePath, new ByteArrayInputStream(file.getBytes()));
            } catch (IOException e) {
                e.printStackTrace();
                return ResponseData.fail("上传失败");
            }
            stars[i] = ossConfig.getImageUrl() + filePath;
//            System.out.println(stars[i]);
        }
        return ResponseData.success(stars);
    }


    public static void main(String args[]) {
        String str = ".jpg/.jpeg/.gif/.png/.mp4/.apk/.ipa";
        String pattern = "[\\u4e00-\\u9fa5]";
        String[] split = str.split("/");
        System.out.println(Arrays.toString(split));

        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(str);
        System.out.println(m.find());
    }


    /**
     * 上传的目录
     * 目录: 根据年月日归档
     * 文件名: 时间戳 + 随机数
     *
     * @param fileName
     * @return
     */
    private static String getFilePath(String fileName, FileInfo fileInfo) {
        Pattern p = Pattern.compile("[\\u4e00-\\u9fa5]");
        Matcher m = p.matcher(fileName);
        if (m.find()) {
            int lastIndexOf = fileName.lastIndexOf(".");
            String suffix = fileName.substring(lastIndexOf);
            fileName = RandomUtil.randomNumbers(fileName.length()) + suffix;
        }
        DateTime dateTime = new DateTime();
        String filePath = "YS-images/" + dateTime.toString("yyyy") + "/" + dateTime.toString("MM") + "/"
                + dateTime.toString("dd") + "/" + System.currentTimeMillis() +
                RandomUtil.randomInt(100, 9999) + fileName;
        if (!ObjectUtils.isEmpty(fileInfo) && !StringUtils.isEmpty(fileInfo.getWidth()) && !StringUtils.isEmpty(fileInfo.getHeight())) {
            filePath =
                    "YS-images/" + dateTime.toString("yyyy") + "/" + dateTime.toString("MM") + "/"
                            + dateTime.toString("dd") + "/" + "(" + fileInfo.getWidth() + "*" + fileInfo.getHeight() + ")" + System.currentTimeMillis() +
                            RandomUtil.randomInt(100, 9999) + fileName;
        }
        return filePath;
    }


    /**
     * 获取视频文件时长S
     *
     * @param contentFile
     * @return
     * @throws Exception
     */
    private static FileInfo getVideoTime(MultipartFile contentFile) throws Exception {
        File f = multipartFileToFile(contentFile);
        FileInfo fileInfo = new FileInfo();
        try {
            // 获取视频时长
            Encoder encoder = new Encoder();
            MultimediaInfo m = encoder.getInfo(f);
            long l = m.getDuration() / 1000;
            log.info(contentFile.getOriginalFilename() + "-----视频时长" + l + "秒");
            f.delete();
            fileInfo.setWidth(m.getVideo().getSize().getHeight());
            fileInfo.setHeight(m.getVideo().getSize().getWidth());
            fileInfo.setTimes(l);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            f.delete();
            f.deleteOnExit();
        }

        return fileInfo;

    }

    /**
     * 获取文件大小KB
     *
     * @param contentFile
     * @return
     * @throws Exception
     */
    public static BigDecimal getFileSize(MultipartFile contentFile) throws Exception {
        File f = multipartFileToFile(contentFile);
        FileInputStream fs = new FileInputStream(f);
        FileChannel fc = fs.getChannel();
        BigDecimal fileSize = new BigDecimal(fc.size());
        fs.close();
        fc.close();
        delteTempFile(f);
        BigDecimal bigDecimal = fileSize.divide(new BigDecimal(1024), 2, RoundingMode.HALF_UP);
        log.info(contentFile.getOriginalFilename() + "-----文件大小" + bigDecimal + "KB");
        return bigDecimal;
    }

    /**
     * 获取图片宽高
     *
     * @param contentFile
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     * @throws Exception
     */
    private static FileInfo getpictureFileInfo(MultipartFile contentFile) throws FileNotFoundException, IOException, Exception {
        File picture = multipartFileToFile(contentFile);
        FileInputStream fs = new FileInputStream(picture);
        BufferedImage sourceImg = ImageIO.read(fs);
        FileInfo fileInfo = new FileInfo();
        fileInfo.setHeight(sourceImg.getHeight());
        fileInfo.setWidth(sourceImg.getWidth());
        fs.close();
        delteTempFile(picture);
//        System.out.println(String.format("Size: %.1f KB", picture.length() / 1024.0));
//        System.out.println("Width: " + sourceImg.getWidth());
//        System.out.println("Height: " + sourceImg.getHeight());
        return fileInfo;
    }

    /**
     * 获取视频文件宽高
     *
     * @param contentFile
     * @return
     * @throws Exception
     */
    private static FileInfo getVideoInfo(MultipartFile contentFile) throws Exception {
        File f = multipartFileToFile(contentFile);
        // 获取视频宽高
        Encoder encoder = new Encoder();
        MultimediaInfo m = encoder.getInfo(f);

        delteTempFile(f);
        return null;

    }

    /**
     * MultipartFile 转 File
     *
     * @param file
     * @throws Exception
     */
    public static File multipartFileToFile(MultipartFile file) throws Exception {

        File toFile = null;
        if ("".equals(file) || file.getSize() <= 0) {
            toFile = null;
        } else {
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            inputStreamToFile(ins, toFile);
            ins.close();
        }
        return toFile;
    }

    //获取流文件
    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除本地临时文件
     *
     * @param file
     */
    public static void delteTempFile(File file) {
        if (file != null) {
            File del = new File(file.toURI());
            del.delete();
        }
    }


    @Data
    private static class FileInfo {
        private Integer width;
        private Integer height;
        private Long times;
    }

}
